/**
 * https://www.bilibili.com/video/BV1vs411n7TH/?p=66
 * 16.指针运算
 *    指针与指针之间, 只能相减(int step = p - arr), 不能 +, *, /, %
 *                  能比较大小: >, <, ...
 *                  能判断等于: ==, !=
 *                  能逻辑判断: if(p && arr) //如果都!=NULL
 *                  赋值     : p = &a;
 *                  自增,自减 : p++, p--
 *                  sizeof   : int size = sizeof(p);
 */
#include <stdio.h>

void str_cpy1(char* dest, const char* source);
void str_cpy2(char* dest, const char* source);
void str_cpy3(char* dest, const char* source);
void str_cpy4(char* dest, const char* source);

void pointer_array();
void multiple_level_pointer();
void swap();
void str_concat();
void remove_space();
char* return_pointer_strchr(char *str, char c);

int main() {
    char source[] = "Hello World!"; //字符数组, 结尾自动带'\0'
    char dest[100];
    /**
     * 1.字符串复制
     */
     //方法1: arr[i]
//    str_cpy1(dest, source);
    //方法2: 指针
//    str_cpy2(dest, source);
    //方法3: 指针
//    str_cpy3(dest, source);
    //方法4. 最简单, 就1行代码
//    str_cpy4(dest, source);
    printf("1.字符串复制: dest[] = %s\n", dest);

    /**
     * 2.指针数组
     */
//    pointer_array();
    //3.多级指针
//    multiple_level_pointer();
    //4.交换a, b的值
//    swap();
    //5.字符串拼接
//    str_concat();
    //6.去掉空格
    remove_space();
    //7.返回指针, 返回字母所在位置.
    char *string = return_pointer_strchr(source, 'W');
    printf("7.返回指针, 返回字母所在位置: = %s\n", string);

    return 0;
}

/**
 * 1.字符复制
 *  方法1: arr[i]
 * @param dest 目标数组
 * @param source 原数组
 */
void str_cpy1(char* dest, const char* source) {
    if(dest == NULL || source == NULL) return;
    int i = 0;
    while (source[i]) { // != '\0'
        dest[i++] = source[i];
//        i ++;
    }
    dest[i] = '\0';     //最后记得加个0结尾
}

//方法2: 指针
void str_cpy2(char* dest, const char* source) {
    if(dest == NULL || source == NULL) return;
    int i = 0;
    char ii;
    while (ii = *(source + i)) {
        *(dest + i++) = ii;
//        i ++;
    }
    dest[i] = '\0';     //最后记得加个0结尾
}

//方法3: 指针
void str_cpy3(char* dest, const char* source) {
    if(dest == NULL || source == NULL) return;
    while (*source) {
        *dest = *source;
        dest ++;
        source ++;
    }
    *dest = 0;
}

//方法4: 最简单, 就1行代码
void str_cpy4(char* dest, const char* source) {
    if(dest == NULL || source == NULL) return;
    while (*dest++ = *source++);
}


/**
 * 2.指针数组, 是一个特殊的 2维数组 模型, 2级指针模型
 */
void pointer_array() {
    int a = 10, b = 20, c = 30;
    int* arrP1[3] = {&a, &b, &c}; //指针数组
    for (int i = 0; i < 3; ++i) {
        printf("*arrP1[%d] = %d  ", i, *arrP1[i]);  //*arr[0] = 10
    }
    puts("");

    int arr0[] = {1, 2, 3};
    int arr1[] = {4, 5, 6};
    int arr2[] = {7, 8, 9};
    int* arrP2[] = {arr0, arr1, arr2};

    //方法1: 指针数组: 是一个特殊的 2维数组 模型
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            //arr[0][0] = 1,
            printf("arr[%d][%d] = %d  ", i, j, arrP2[i][j]);
        }
        puts("");
    }

    //方法2: 数组+指针
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            printf("*(arr[%d] + %d) = %d  ", i, j, *(arrP2[i] + j));  //*(arr[0] + 0) = 1
        }
        puts("");
    }

    //方法3: 指针套指针, 2级指针模型
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            printf("*(*(arr + %d) + %d) = %d  ", i, j, *(*(arrP2 + i) + j));  //*(*(arr + 0) + 0) = 1
        }
        puts("");
    }
}


/**
 * 3.多级指针, multiple /ˈmʌltɪp(ə)l/ a.多个的
 */
void multiple_level_pointer() {
    int arr0[] = {1, 2, 3};
    int arr1[] = {4, 5, 6};
    int arr2[] = {7, 8, 9};
    int* arrP2[] = {arr0, arr1, arr2};

    int **pp = arrP2;       //2级数组&指针数组
    printf("**pp = %d\n", **pp);                        //1
    printf("**(pp + 1) = %d\n", **(pp + 1));            //4
    printf("*(*pp + 2) = %d\n", *(*pp + 2));            //3
    printf("*(*(pp + 1) + 1) = %d\n", *(*(pp + 1) + 1));//5
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
//            printf("arr[%d][%d] = %d  ", i, j, arrP2[i][j]);                //arr[0][0] = 1
//            printf("*(arr[%d] + %d) = %d  ", i, j, *(arrP2[i] + j));        //*(arr[0] + 0) = 1
            printf("*(*(arr + %d) + %d) = %d  ", i, j, *(*(arrP2 + i) + j));//*(*(arr + 0) + 0) = 1
        }
        puts("");
    }
}

//https://www.bilibili.com/video/BV1vs411n7TH?p=69
//4.交换a, b的个值
void swap() {
    int a = 10, b = 20;
    printf("a = %d, b = %d\n", a, b);
    int *p1 = &a, *p2 = &b;
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    printf("4.swap()后: a = %d, b = %d\n", a, b);
}

//5.字符串拼接 https://www.bilibili.com/video/BV1vs411n7TH?p=70
void str_concat() {
    char s1[100] = "hello", s2[] = "world";
    char *p1 = s1;
    while (*p1) {       //当 != '\0'时, 要去掉结尾的'\0'
        p1 ++;
    }
    char *p2 = s2;
//    while (*p2) {     //1.这种可以
//        *p1 = *p2;
//        p1 ++;
//        p2 ++;
//    }
//    while (*p2) {     //2.这种可以
//        *p1++ = *p2++;
//    }
    while (*p1++ = *p2++);//3.这种可以

    printf("5.字符串拼接: %s\n", s1);     //helloworld
}

//6.去掉空格 https://www.bilibili.com/video/BV1vs411n7TH?p=71
void remove_space() {
//    char *str = " He l   lo W or l d ! "; //必须是数组, 如果是字符串会报错.
    char str[] = " He l   lo W or l d ! ";
    char *record = str; //记录非空字符串位置
    char *temp = str;   //遍历字符串
    while (*temp) {
        if(*temp != ' ') {
            *record = *temp;
            record++;
        }
        temp++;
    }
    *record = 0;
    printf("6.去掉空格后: %s\n", str);
}

//7.返回指针, 返回字母所在位置. https://www.bilibili.com/video/BV1vs411n7TH?p=72
char* return_pointer_strchr(char *str, char c) {
    //方法1: 数组
//    int i = 0;
//    while (str[i]) {
//        if(str[i] == c) {
//            return &str[i];
//        }
//        i++;
//    }
    //方法2: 指针
    while (*str) {
        if (*str == c) {
            return str;
        }
        str++;
    }
    return NULL;
}
